home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-10-05 | 8.6 KB | 259 lines | [TEXT/MPS ] |
- #
- # File: TowersOfHanoi.vu
- #
- # Contains: The script solves the problem of 'Towers of Hanoi' using Finder windows
- # as 'towers'.
- #
- # To be able to run this script, the target should be in
- # Finder, with either a window open or a volume selected.
- # Also, set the following variables towards the end of this file:
- # (Default values are in parens)
- # Total_disks(3) : the number of disks you want the towers to be built with.
- # From_tower(1) : the tower from which you want to move;
- # To_tower(3) : the tower to which you want to move;
- # Using_tower(2) : the tower which will be used as a temporary one;
- # System7(false) : whether or not you're running System 7
- #
- # Conventions: Global variables begin with a capital letter
- #
- # Warning: This script will create a set of folders in the open/selected volume.
- # So do trash these folders after the script completes its execution.
- # Also, if the folders with the names used already exist (from previous execution)
- # the script will not work.
- #
- # Written by: P Nagarajan
- #
- # Copyright: © 1990 by Apple Computer, Inc., all rights reserved.
- #
- # Change History:
- #
- # 5/17/90 JAS A few formatting changes
- #
- # 3/29/89 naga Creation
- #
- #
- # To Do:
- #
-
-
- # ********************************************************************************************
- task insert_into_list(element, position, lst)
- # This task inserts/replaces an 'element' at 'position' in a list contained
- # in the argument 'lst', and returns the new list.
- # 'position' must be an Integer.
- # Prerequisites:: Presence of a list in 'lst'.
- begin
- local_list := {};
- for pos := 1 to (position - 1) do
- local_list := local_list + {lst[pos]};
- local_list := local_list + {element};
- size_of_list := card(lst);
- for pos := (position + 1) to size_of_list do
- local_list := local_list + {lst[pos]};
- return local_list;
- end; #task insert_into_list
-
-
-
- # ********************************************************************************************
- task add_move(from_t, to_t, all_moves)
- # Adds a move of the form {from_t, to_t} to the global list 'all_moves'.
- # All Arguments should be integers
- begin
- all_moves := all_moves + {{from_t, to_t}};
- return all_moves;
- end;
-
-
- # ********************************************************************************************
- task gen_moves(from_t, to_t, using, num_disks, all_moves)
- # Generates moves for moving 'num_disks' number of disks from 'from_t' tower
- # to 'to_t' tower using 'using' tower
- # All Arguments should be integers
- begin
- if not (num_disks = 0) do
- begin
- if (num_disks = 1) do
- return add_move(from_t, to_t, all_moves);
- else do
- begin
- all_moves := gen_moves(from_t, using, to_t, num_disks - 1, all_moves);
- all_moves := add_move(from_t, to_t, all_moves);
- all_moves := gen_moves(using, to_t, from_t, num_disks - 1, all_moves);
- return all_moves;
- end;
- end;
- end; #task gen_moves
-
-
- # ********************************************************************************************
- task set_up_tower(tower, no_of_disks)
- # Sets up the tower called Tower{tower} made of 'no_of_disks'
- # Prereqs:: 'Base_dimension' : an integer specifying the size of the base disk(window)
- # 'Position_of_tower' : a list having the initial position of each tower,
- # position being {x, y}.
- # Results:: 'Delta_for_tower' : sets up this global list, which gives the displacement of the topmost
- # disk from the base, on each tower. ( a list of 3 integers).
- # 'success' : if setup successful returns true else false.
- begin
- global Screen_rect;
- global Base_dimension;
- global Position_of_tower;
-
- j := tower; #tower number
- i := no_of_disks;
- all_windows := collect[window];
- if (card(all_windows) = 1) do
- begin
- Drag [Window] a: {Screen_rect[3]-12, Screen_rect[4]-50};
- Select [MenuItem t: 'New Folder' m:'File'];
- Type k:{"Tower{j}"};
- Select [MenuItem t:'Open' m:'File'];
- Drag [Window t:"Tower{j}"] a: {1,20};
- Size [Window t:"Tower{j}"] h: Base_dimension w:Base_dimension;
- Drag [Window t:"Tower{j}"] a: {Screen_rect[3]-12, Screen_rect[4]-50};
- global Delta_for_tower := {0,0,0};
- delta_move := Delta_for_tower[j];
- while (i > 0) do
- begin
- Select [Window t:"Tower{j}"];
- Select [MenuItem t: 'New Folder' m:'File'];
- Type k:{"Disk{i}"};
- Select [MenuItem t:'Open' m:'File'];
- new_position := {(Position_of_tower[j][1] + delta_move),
- (Position_of_tower[j][2] - delta_move) };
- Drag [Window t:"Disk{i}"] a: {1,20};
- Size [Window t:"Disk{i}"] h:Base_dimension - delta_move/2 w:Base_dimension - 2*delta_move;
- Drag [Window t:"Disk{i}"] a: new_position;
- delta_move := delta_move + 5;
- i := i - 1;
- end;
- Delta_for_tower := insert_into_list((delta_move - 5), j, Delta_for_tower);
- success := true;
- end; #if one open window exists
- else do #try to open a single window
- begin
- if (card(all_windows) > 1) do
- for each w in all_windows do
- if w.c close[window];
- all_windows := collect[window];
- if (card(all_windows) = 0) or (global System7) do
- begin
- if (match [menuItem t:'Open' m:'File' e:true]!) do
- begin
- select [menuItem t:'Open' m:'File']!;
- success := set_up_tower(tower, no_of_disks);
- end; #if a window can be opened thru' the menu
- else do
- success := false;
- end; #no windows currently
- else do #could not close all windows
- success := false;
- end; #opened a single window
- return success;
- end; #task set_up_tower
-
-
- # ********************************************************************************************
- task make_moves(all_moves)
- #this task actually makes the moves (dragging windows) using the moves,
- #stored in the argument 'all_moves'.
- #Prereqs :: 'all_moves' a list containing moves of form {i,j}
- # 'Position_of_tower' : a list having the initial position of each tower,
- # position being {x, y}.
- # 'Delta_for_tower' : a list which gives the displacement for the next disk
- # to be placed on a tower (from the original position of the tower).
- begin
- global Delta_for_tower;
- global Position_of_tower;
-
- x := 1; #index to get x-coord
- y := 2; #index to get y-coord
- for each disk_move in all_moves do
- begin
- i := disk_move[1] ;
- j := disk_move[2] ; #move from tower i to tower j
- delta_move := Delta_for_tower[j] + 5;
- newx := Position_of_tower[j][x] + delta_move;
- newy := Position_of_tower[j][y] - delta_move;
- new_position := {newx, newy};
- wind_rect := {Position_of_tower[i][x] + Delta_for_tower[i], #left
- Position_of_tower[i][y] - Delta_for_tower[i], #top
- 0 ,#right
- 0 #bottom
- };
- Select [Window r:?rect1:wind_rect];
- Drag [Window] a: new_position;
- Delta_for_tower := update_Delta_for_tower(delta_move, i, j, Delta_for_tower);
- end; #for_each move
- end; #task make_moves
-
-
- # ********************************************************************************************
- task update_Delta_for_tower(delta_move, from_t, to_t, Delta_for_tower)
- begin
- if (Delta_for_tower[from_t] <> 0) do
- Delta_for_tower := insert_into_list((Delta_for_tower[from_t] - 5), from_t, Delta_for_tower);
- Delta_for_tower := insert_into_list(delta_move, to_t, Delta_for_tower);
- return Delta_for_tower;
- end; #task update_Delta_for_tower
-
-
-
- ##### EXECUTION STARTS HERE ######
-
- Total_disks := 3;
- From_tower := 1;
- To_tower := 3;
- Using_tower := 2;
- System7 := false;
-
- All_moves := {};
-
- if (System7) Patience(2);
-
- match[screen r:?Screen_rect m:true];
- screen_width := Screen_rect[3]- Screen_rect[1];
- screen_height := Screen_rect[4]- Screen_rect[2];
- Max_disks1 := ((Screen_height - 20) - 112)/5;
- Max_disks2 := (((Screen_width - 30)/3) - 112)/5;
- if Max_disks2 >= Max_disks1 #find the tighter of the two bounds
- begin
- Max_disks := Max_disks1;
- end;#if
- else
- begin
- Max_disks := Max_disks2;
- end;#if
- if Total_disks > Max_disks
- begin
- println "Sorry can draw only tower with a maximum of ", Max_disks,
- " disks on this target's main screen.";
- println "Try with lesser number of disks or a larger screen!";
- end;#if
- else
- begin
- Base_dimension := 117 + 5*(Total_disks - 1);
- X_offset := (Screen_width-Base_dimension*3)/4;
- Y_offset := (Screen_height-Base_dimension)/2;
- Position_of_tower := {{(Screen_rect[1] + X_offset),(Screen_rect[2] + Y_offset)},
- {(Screen_rect[1] + X_offset*2 + Base_dimension), (Screen_rect[2] + Y_offset)},
- {(Screen_rect[1] + X_offset*3 + Base_dimension*2), (Screen_rect[2] + Y_offset)}};
-
- println "Now computing the moves...";
- All_moves := gen_moves(From_tower, To_tower, Using_tower, Total_disks, All_moves);
- println "done!";
- println "Now setting up the tower of disks...";
- Success := set_up_tower(From_tower, Total_disks);
- if (Success) do
- begin
- println "done!";
- println "Now making the moves...";
- make_moves(All_moves);
- println "done!";
- end;
- else do
- println "Target not set up to solve the problem. Sorry.";
- end;#else Total_disks permissible
-
-